/*
 * server.c
 *
 *  Created on: 28 nov. 2013
 *      Author: SAGUET Julien et POCREAU Aymeric
 */
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <netinet/in.h>

#include "../includes/server.h"
#include "../includes/common.h"

#define PORT 33000
#define MAXBUF 1024

int main(int argc, char* argv[]) {
	int port;
	char *endptr = NULL; // for strtol()
	int socketEcoute;
	fd_set readfds;
	listeClients liste = NULL;
	client_t* Client = NULL;
	ban_t* listebans = NULL;
	groupe_t* listeGroupes = NULL;
	int max = 0;
	int conn_s;
	char buffer[MAXBUF];
	int ret;
	char* pseudo = NULL;
	struct sockaddr_in clientaddr;
	socklen_t size;

	// Usage
	if (argc == 2) {
		port = strtol(argv[1], &endptr, 0);
		if (*endptr) {
			fprintf(stderr, "ECHOSERV : Invalid port number\n");
			exit(EXIT_FAILURE);
		}
	} else if (argc < 2) {
		port = PORT;
	} else {
		fprintf(stderr, "ECHOSERV: Invalid arguments\n");
		exit(EXIT_FAILURE);
	}

	// Création d'une socket d'écoute
	socketEcoute = create_socket(INADDR_ANY, port);
	max = socketEcoute;

	// Boucle infinie pour repondre aux différentes requetes
	while (1) {

		FD_ZERO(&readfds);
		FD_SET(socketEcoute, &readfds);

		// Ajouter les sockets de chaque clients a l ensemble des descripteurs de fichier
		if (liste != NULL) {
			client_t* temp = liste;
			while (temp != NULL) {
				FD_SET(temp->socket, &readfds);
				temp = temp->next;
			}
		}
		if (select(max + 1, &readfds, NULL, NULL, NULL) < 0) {
			perror("select");
			return EXIT_FAILURE;
		}

		// Connection d'un nouveau client
		if (FD_ISSET(socketEcoute, &readfds)) {
			size = sizeof(clientaddr);

			if ((conn_s = accept(socketEcoute, (struct sockaddr *) &clientaddr, &size)) < 0) {
				perror("accept");
				exit(EXIT_FAILURE);
			}

			// On cherche le nouveau max :
			max = conn_s > max ? conn_s : max;

			// Récupération du pseudo
			pseudo = new_client_name(conn_s, liste);

			// On regarde s'il n'a pas encore été banni
			ban_t* tmp = listebans;
			while (tmp != NULL) {
				fprintf(stdout, "Pseudo tmp : %s", tmp->pseudo);
				if (!strcmp(tmp->pseudo, pseudo)) {
					sendline(conn_s,
							"Connexion impossible, vous avez été banni.\n",
							strlen(
									"Connexion impossible, vous avez été banni.\n"));
					close(conn_s);
					break;
				}
				tmp = tmp->next;
			}

			// Si ce n'est pas le cas, on l'ajoute à la liste
			if (tmp == NULL) {
				liste = ajouterClient(liste, conn_s, pseudo, clientaddr);

				// On lui propose de se créer un compte, ou de s'y connecter s'il existe déjà
				gestionComptes(conn_s, pseudo);
			}

		// Activité sur un client déjà connecté
		} else {
			Client = liste;

			// On regarde quel est le client qui parle, et on execute les actions
			while (Client != NULL) {
				if (FD_ISSET(Client->socket, &readfds)) {
					memset(buffer, 0, MAXBUF - 1);

					// On récupère ce qu'a envoyé le client
					ret = readline(Client->socket, buffer, MAXBUF - 1);

					if (ret > 0) {
						fprintf(stdout, "echo>%s", buffer);

						// On effectue différentes actions selon la commande reçue
						checkAction(liste, Client, buffer, &listeGroupes,
								&listebans);
					}
					// Client déconnecté
					else if (ret <= 0) {
						printf("%s: socket %d hung up\n", argv[0], conn_s);

						// On retire le client de la liste.
						liste = deleteFromList(Client->socket, liste);
					}
				}
				Client = Client->next;
			}
		}
	}
	return EXIT_SUCCESS;
}

